package grpcUtils

import (
	"context"
	"github.com/gin-gonic/gin"
	"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
	"golang.org/x/net/http2"
	"golang.org/x/net/http2/h2c"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"log"
	"net"
	"net/http"
	"strings"
)

type gateWayHandle = func(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts ...grpc.DialOption)

type GrpcServer struct {
	grpcServer *grpc.Server
	mux        *runtime.ServeMux
}

func (g *GrpcServer) CloseGrpcServer() {
	g.grpcServer.Stop()
}
func (g *GrpcServer) MuxToGinHandle() gin.HandlerFunc {
	return gin.WrapH(g.mux)
}

func (g *GrpcServer) RegisterFromEndpoint(gatewayPort string, handles ...gateWayHandle) {
	//批量注册
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	//ctx := context.Background()
	for _, item := range handles {
		item(ctx, g.mux, gatewayPort, grpc.WithTransportCredentials(insecure.NewCredentials()))
	}
}

// RunGrpcServer 注册Grpc

func (g *GrpcServer) RegisterServer(handles func(s grpc.ServiceRegistrar)) {
	//批量注册
	handles(g.grpcServer)
	//reflection.Register(global.grpcServer)
}

// RunGrpcServer 启动Grpc
func (g *GrpcServer) RunGrpcServer(grpcPort string) {
	lis, err := net.Listen("tcp", grpcPort)
	if err != nil {
		log.Fatalf("failed to listen: %v", err)
	}
	if err := g.grpcServer.Serve(lis); err != nil {
		log.Fatalf("failed to serve gRPC: %v", err)
	}

}
func grpcHandlerFunc(grpcServer *grpc.Server, otherHandler http.Handler) http.Handler {
	return h2c.NewHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.ProtoMajor == 2 && strings.Contains(r.Header.Get("Content-Type"), "application/grpc") {
			grpcServer.ServeHTTP(w, r)
		} else {
			otherHandler.ServeHTTP(w, r)
		}
	}), &http2.Server{})
}

func (g *GrpcServer) RunGateWay(gatewayPort string) {
	http.ListenAndServe(gatewayPort, grpcHandlerFunc(g.grpcServer, g.mux))
	//http.ListenAndServe(global.gatewayPort, global.mux)
}

func (g *GrpcServer) RunGateWayGin(r *gin.Engine, gatewayPort string) {
	h2Handle := h2c.NewHandler(r.Handler(), &http2.Server{})
	server := &http.Server{
		Addr:    gatewayPort,
		Handler: h2Handle,
	}
	server.ListenAndServe()
}

func NewGrpcGinServer() *GrpcServer {
	return &GrpcServer{
		grpc.NewServer(), runtime.NewServeMux(),
	}
}
